#include "raft_core/RaftSender.h"

#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/security/credentials.h>
#include <grpcpp/support/status.h>

#include "raft_utils/Config.h"

raft::core::RaftSender::RaftSender(const std::string& ip, short port)
    : log(bq::log::get_log_by_name(raft::utils::Config::getInstance()->get_log_name())) {
    me_ = ip + ':' + std::to_string(port);
    std::string target_str = me_;
    auto channel = grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials());
    stub_ = raft_rpc_protoc::RaftRPC::NewStub(channel);
}

bool raft::core::RaftSender::append_entries(const raft_rpc_protoc::AppendEntries& request,
                                            raft_rpc_protoc::AppendEntriesReply* reply) {
    log.verbose("Start: raft::core::RaftSender::append_entries(const raft_rpc_protoc::AppendEntries& request,...)");

    grpc::ClientContext context;
    grpc::Status status = stub_->append_entries(&context, request, reply);
    if (!status.ok()) {
        log.warning("[func-raft::core::RaftSender::append_entries] rpc failed");
        log.verbose("End: bool raft_core::RaftRpc::append_entries(const raft_rpc_protoc::AppendEntries& request, raft_rpc_protoc::AppendEntriesReply *reply)");
        return false;
    }

    log.verbose("End: raft::core::RaftSender::append_entries(const raft_rpc_protoc::AppendEntries& request,...)");
    return true;
}

bool raft::core::RaftSender::request_election(const raft_rpc_protoc::RequestElection& request,
                                              raft_rpc_protoc::RequestElectionReply* reply) {
    log.verbose("Start: bool raft_core::RaftRpc::request_vote(const raft_rpc_protoc::RequestVote& request, raft_rpc_protoc::RequestVoteReply* reply)");

    grpc::ClientContext context;
    grpc::Status status = stub_->request_election(&context, request, reply);
    if (!status.ok()) {
        log.warning("[func-raft::core::RaftSender::request_vote] rpc failed");
        log.verbose("End: bool raft::core::RaftSender::request_vote(const raft_rpc_protoc::RequestVote& request, raft_rpc_protoc::RequestVoteReply* reply)");
        return false;
    }

    log.verbose("End: bool raft::core::RaftSender::request_vote(const raft_rpc_protoc::RequestVote& request, raft_rpc_protoc::RequestVoteReply* reply)");
    return true;
}

bool raft::core::RaftSender::install_snapshot(const raft_rpc_protoc::InstallSnapshot& request,
                                              raft_rpc_protoc::InstallSnapshotReply* reply) {
    log.verbose("Start: bool raft::core::RaftSender::install_snapshot(const raft_rpc_protoc::InstallSnapshot& request, raft_rpc_protoc::InstallSnapshotReply* reply)");
    grpc::ClientContext context;
    grpc::Status status = stub_->install_snapshot(&context, request, reply);
    if (!status.ok()) {
        log.warning("[func-raft::core::RaftSender::install_snapshot] rpc failed");
        log.verbose("End: bool raft::core::RaftSender::install_snapshot(const raft_rpc_protoc::InstallSnapshot& request, raft_rpc_protoc::InstallSnapshotReply* reply)");
        return false;
    }

    log.verbose("End: bool raft::core::RaftSender::install_snapshot(const raft_rpc_protoc::InstallSnapshot& request, raft_rpc_protoc::InstallSnapshotReply* reply)");
    return true;
}

std::string raft::core::RaftSender::get_me() const {
    return me_;
}